﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Web;
using System.Web.Caching;
using System.Web.Security;
using System.Xml;
using LitJson;
using Xproject.Util; 
namespace Core.WeiXin
{
    /// <summary>
    /// WeiXinHelper 的摘要说明
    /// </summary>
    public static class WeiXinHelper
    {
        public static string AppID = WxPayConfig.APPID;
        public static string AppSecret = WxPayConfig.APPSECRET;
      
        public static string GetCodeUrl(string redirect_uri)
        {
            return GetCodeUrl(WeiXinHelper.AppID, redirect_uri);
        }
        public static string GetCodeUrl(string appId, string redirect_uri)
        {
            return GetCodeUrl(appId, redirect_uri, "STATE");
        }
        public static string GetCodeUrl(string appId, string redirect_uri, string state)
        {
            return string.Format(@"https://open.weixin.qq.com/connect/oauth2/authorize?appid={0}&redirect_uri={1}&response_type=code&scope=snsapi_userinfo&state={2}#wechat_redirect", appId, redirect_uri, state);
        }
        public static string GetCodeUrl2(string appId, string redirect_uri, string state)
        {
            return string.Format(@"https://open.weixin.qq.com/connect/oauth2/authorize?appid={0}&redirect_uri={1}&response_type=code&scope=snsapi_base&state={2}#wechat_redirect", appId, redirect_uri, state);
        }
        public static WeiXinModel.UserInfoModel GetUserInfo(string code)
        {
            return GetUserInfo(AppID, AppSecret, code);
        }
        public static WeiXinModel.GetToken GetUserOpenId(string appId, string appSecret, string code)
        {
            try
            {                
                LogHelper.WriteInfoLog("code=" + code);
                string jsondata = HttpGet("https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + appId + "&secret=" + appSecret + "&code=" + code + "&grant_type=authorization_code");                
                LogHelper.WriteInfoLog("jsondata=" + jsondata);
                WeiXinModel.GetToken data = JsonMapper.ToObject<WeiXinModel.GetToken>(jsondata);
                return data;
            }
            catch (Exception ex)
            {
                LogHelper.WriteErrorLog("WeiXinHelper.GetUserOpenId Happen ERROR: "+ex.Message + " >>>> ParamList: appid= " + appId + " appSecret ="+ appSecret+ " code="+ code, ex);                
            }

            return new WeiXinModel.GetToken();
        }
        public static WeiXinModel.UserInfoModel GetUserInfo(string appId, string appSecret, string code)
        {
            WeiXinModel.UserInfoModel userinfo = new WeiXinModel.UserInfoModel();
            try
            {
                WeiXinModel.GetToken data = GetUserOpenId(appId, appSecret, code);
                string openid = data.openid;
              
                string userinfodata = HttpGet("https://api.weixin.qq.com/sns/userinfo?access_token=" + (string)data.access_token + "&openid=" + openid + "&lang=zh_CN");
                              userinfo = JsonMapper.ToObject<WeiXinModel.UserInfoModel>(userinfodata);
            }
            catch (Exception ex)
            {
                LogHelper.WriteErrorLog("WeiXinHelper.GetUserInfo Happen ERROR: " + ex.Message + " >>>> ParamList: appid= " + appId + " appSecret =" + appSecret + " code=" + code, ex);              
            }

            return userinfo;
        }
        public static WeiXinModel.UserInfoModel GetUserInfoByOpenId(string openId)
        {
            WeiXinModel.UserInfoModel userinfo = new WeiXinModel.UserInfoModel();
            try
            {
                WeiXinModel.TokedataDataModel token = GetToken();
                userinfo = GetUserInfoByOpenId(token, openId);
            }
            catch (Exception ex)
            {
                LogHelper.WriteErrorLog("WeiXinHelper.GetUserInfoByOpenId Happen ERROR: " + ex.Message + " >>>> ParamList: openId= " + openId , ex);               
            }
            return userinfo;
        }
        public static WeiXinModel.UserInfoModel GetUserInfoByOpenId(string appId, string appSecret, string openId)
        {
            WeiXinModel.UserInfoModel userinfo = new WeiXinModel.UserInfoModel();
            try
            {
                WeiXinModel.TokedataDataModel token = GetTokenModel(appId, appSecret);
                userinfo = GetUserInfoByOpenId(token, openId);
            }
            catch (Exception ex)
            {
                LogHelper.WriteErrorLog("WeiXinHelper.GetUserInfoByOpenId Happen ERROR: " + ex.Message + " >>>> ParamList: appid= " + appId + " appSecret =" + appSecret + " openId=" + openId, ex);                
            }
            return userinfo;
        }
        public static WeiXinModel.UserInfoModel GetUserInfoByOpenId(WeiXinModel.TokedataDataModel token, string openId)
        {
            WeiXinModel.UserInfoModel userinfo = new WeiXinModel.UserInfoModel();
            try
            {
               // LogHelper.WriteInfoLog("=========================== start"+ token.access_token);
                string url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token={0}&openid={1}&lang=zh_CN";
                string userinfodata = HttpGet(string.Format(url, token.access_token, openId));
               // LogHelper.WriteInfoLog("=========================== end"+ userinfodata);                
                userinfo = JsonMapper.ToObject<WeiXinModel.UserInfoModel>(userinfodata);
            }
            catch (Exception ex)
            {
                LogHelper.WriteErrorLog("WeiXinHelper.GetUserInfoByOpenId Happen ERROR: " + ex.Message + ">>>> ParamList: openId=" + openId, ex);                
            }
            return userinfo;
        }

        public static string HttpGet(string Url)
        {
            try
            {
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Url);
                request.Method = "GET";
                request.ContentType = "text/html;charset=UTF-8";
                HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                Stream myResponseStream = response.GetResponseStream();
                StreamReader myStreamReader = new StreamReader(myResponseStream, Encoding.UTF8);
                string retString = myStreamReader.ReadToEnd();
                myStreamReader.Close();
                myResponseStream.Close();
                return retString;
            }
            catch (Exception ex)
            {
                LogHelper.WriteErrorLog("WeiXinHelper.HttpGet Happen ERROR: " + ex.Message + ">>>> ParamList: Url=" + Url, ex);
                return ex.ToString();
            }
        }

        public static WeiXinModel.TokedataDataModel GetToken()
        {
            return GetTokenModel();
        }
        public static WeiXinModel.TokedataDataModel GetTokenModel()
        {
            return GetTokenModel(WeiXinHelper.AppID, WeiXinHelper.AppSecret);
        }
        public static WeiXinModel.TokedataDataModel GetTokenModel(string appId, string appSecret)
        {
            return GetTokenModel(appId, appSecret, true);
        }
        public static WeiXinModel.TokedataDataModel GetTokenModel(string appId, string appSecret, bool useCache)
        {           
            WeiXinModel.TokedataDataModel tokedata = JsonMapper.ToObject<WeiXinModel.TokedataDataModel>(GetToken(appId, appSecret, useCache));
            return tokedata;
        }
        public static string GetToken(string appId, string appSecret, bool useCache)
        {
            if (useCache == true)
            {
                //
                if (string.IsNullOrEmpty(Cache_WeiXinConfig.WeiXinToken))
                {
                    Cache_WeiXinConfig.WeiXinToken= GetTokenValue(appId, appSecret);
                }
                return Cache_WeiXinConfig.WeiXinToken;

            }
            else
            {
                return GetTokenValue(appId, appSecret);
            }
                  
        }
        public static string GetToken(string appId, string appSecret)
        {
            return GetToken(appId, appSecret, true);
        }
        public static string GetTokenValue(string appId, string appSecret)
        {
            string tokenStr = HttpGet("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appId +
                             "&secret=" + appSecret + "");
            WeiXinModel.TokedataDataModel tokedata = JsonMapper.ToObject<WeiXinModel.TokedataDataModel>(tokenStr);
            if (!string.IsNullOrEmpty(tokedata.access_token))
            {
                Log.Debug(" WeiXinHelper GetTokenValue: ", tokedata.access_token);
            }
            return tokenStr;
        }

        private static string _wxJsApiParam;
        public static string wxJsApiParam
        {
            get { return _wxJsApiParam; }
            set { _wxJsApiParam = value; }
        }
        private static string _appId;
        public static string appId
        {
            get { return _appId; }
            set { _appId = value; }
        }
        private static string _timeStamp;
        public static string timeStamp
        {
            get { return _timeStamp; }
            set { _timeStamp = value; }
        }

        private static string _nonceStr;
        public static string nonceStr
        {
            get { return _nonceStr; }
            set { _nonceStr = value; }
        }

        private static string _signature;
        public static string signature
        {
            get { return _signature; }
            set { _signature = value; }
        }
        private static string _spackage;
        public static string spackage
        {
            get { return _spackage; }
            set { _spackage = value; }
        }

        private static string _paySign;
        public static string paySign
        {
            get { return _paySign; }
            set { _paySign = value; }
        }

        public static string GetWxConfig()
        {
            if (HttpContext.Current.Request.Url.ToString().ToLower().Contains("http://localhost")) return "";
            string token = GetToken(AppID, AppSecret);
            WeiXinModel.TokedataDataModel tokedata = JsonMapper.ToObject<WeiXinModel.TokedataDataModel>(token);
            WeiXinModel.Api_ticket jsapi_ticket =
            JsonMapper.ToObject<WeiXinModel.Api_ticket>(HttpGet("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" + tokedata.access_token + "&type=jsapi"));

            WxPayData jsApiParam = new WxPayData();
            jsApiParam.SetValue("jsapi_ticket", jsapi_ticket.ticket);
            jsApiParam.SetValue("noncestr", WxPayApi.GenerateNonceStr());
            jsApiParam.SetValue("timestamp", WxPayApi.GenerateTimeStamp());
            jsApiParam.SetValue("url", System.Web.HttpContext.Current.Request.Url.AbsoluteUri);

            //jsApiParam.SetValue("signature", FormsAuthentication.HashPasswordForStoringInConfigFile(jsApiParam.ToUrl(), "SHA1"));
            jsApiParam.SetValue("signature", CommonHelper.SHA1(jsApiParam.ToUrl()));
            jsApiParam.SetValue("appId", AppID);
            return jsApiParam.ToJson();
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="payId">系统的订单ID</param>
        /// <param name="userid">传入的参数那个用户</param>
        /// <param name="openid"></param>
        /// <param name="money"></param>
        /// <param name="projectid">一般指商品ID 非微信支付必要参数 </param>
        /// <param name="body"> 商品描述</param>
        /// <param name="attach">附加数据 系统附件的内容 127字以内</param>
        /// <param name="detail"> 商品详情</param>
        /// <param name="trade_type">交易类型 JSAPI 公众号支付    NATIVE 扫码支付 APP APP支付</param>
        /// <param name="goods_tag">订单优惠标记</param>
        /// <returns></returns>
        public static WeiXinModel.WxJsApiParam Pay(string payId, string userid, string openid, decimal money, string projectid, string body, string attach, string detail, string trade_type, string goods_tag)
        {
            JsApiPay jsApiPay = new JsApiPay();
            jsApiPay.openid = openid;
            jsApiPay.total_fee = Convert.ToInt32(money * 100);
            //jsApiPay.total_fee = 1 ;

            string token = GetToken(AppID, AppSecret);
            WeiXinModel.TokedataDataModel tokedata = JsonMapper.ToObject<WeiXinModel.TokedataDataModel>(token);
            WeiXinModel.Api_ticket jsapi_ticket =
            JsonMapper.ToObject<WeiXinModel.Api_ticket>(HttpGet("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" + tokedata.access_token + "&type=jsapi"));

            WxPayData unifiedOrderResult = jsApiPay.GetUnifiedOrderResult(userid, payId,body,attach,detail,trade_type,goods_tag);
            wxJsApiParam = jsApiPay.GetJsApiParameters();

            WeiXinModel.WxJsApiParam result = JsonMapper.ToObject<WeiXinModel.WxJsApiParam>(wxJsApiParam);
            WxPayData sdata = new WxPayData();
            sdata.SetValue("jsapi_ticket", jsapi_ticket.ticket);
            sdata.SetValue("noncestr", result.nonceStr);
            sdata.SetValue("timestamp", result.timeStamp);
            string url = sdata.ToUrl();

            result.signature = CommonHelper.SHA1(url); 
            //    result.signature = SecretHelper.EncryptToSHA1( url ); ;

            return result;
        }
        public static Dictionary<string, string> ReceivePostXmlData(string xmlData)
        {
            if (!string.IsNullOrEmpty(xmlData))
            {
                XmlDocument doc = new XmlDocument();
                doc.LoadXml(xmlData);
                //得到XML文档根节点
                XmlElement root = doc.DocumentElement;
                XmlNodeList nodeList = root.ChildNodes;
                Dictionary<string, string> dic = new Dictionary<string, string>();
                foreach (XmlNode node in nodeList)
                {
                    dic.Add(node.Name, node.InnerText);
                }
                return dic;
            }
            return null;
        }

        public static WeiXinModel.WxJsApiParam Pay(string PayId,string UserID,decimal PayMoney,string ProjectID, string openId
            , string body, string attach, string detail, string trade_type, string goods_tag)
        {
            return Pay(PayId,  UserID, openId,  PayMoney,  ProjectID,body,attach,detail,trade_type,goods_tag);
        }


        public static string CreateQRCodeUrl(string product_id, string out_trade_no, decimal orderMoney, string payName, string url)
        {
            string unifiedorderURL = "https://api.mch.weixin.qq.com/pay/unifiedorder";
            Dictionary<string, string> dic = new Dictionary<string, string>();
            dic.Add("appid", WxPayConfig.APPID);
            dic.Add("mch_id", WxPayConfig.MCHID);
            dic.Add("nonce_str", Guid.NewGuid().ToString("N"));
            dic.Add("product_id", product_id);
            dic.Add("body", payName);
            dic.Add("out_trade_no", out_trade_no);
            dic.Add("total_fee", Convert.ToInt32(orderMoney * 100).ToString());//这里单位是分
            // dic.Add( "total_fee" , "1" );
            dic.Add("notify_url", url);
            dic.Add("trade_type", "NATIVE");
            string returnurl = Codeurl(dic, unifiedorderURL);
            return returnurl;
        }
        public static string Codeurl(Dictionary<string, string> dic, string url)
        {
            string sign = GetSign(dic);
            dic.Add("sign", sign);
            string xml = ArrayToXml(dic);
            Dictionary<string, string> resultdic = ReceivePostXmlData(HttpService.Post(xml, url));
            if (resultdic != null && resultdic["code_url"] != null)
            {
                return resultdic["code_url"];
            }
            return null;
        }
        public static string GetSign(Dictionary<string, string> paraDic)
        {
            Dictionary<string, string> bizParameters = new Dictionary<string, string>();
            foreach (KeyValuePair<string, string> item in paraDic)
            {
                if (item.Value != "")
                {
                    bizParameters.Add(item.Key.ToLower(), item.Value);
                }
            }
            bizParameters = DictionarySort(bizParameters);
            string str = FormatBizQueryParaMap(bizParameters, false);//不进行URL编码，官网文档没有写
            string strSginTemp = string.Format("{0}&key={1}", str, WxPayConfig.KEY);//商户支付密钥 
            string sign = MD5Encrypt(strSginTemp).ToString().Replace("-", "").ToUpper();//转换成大写         
            return sign;
        }
        public static string ArrayToXml(Dictionary<string, string> arr)
        {
            String xml = "<xml>";

            foreach (KeyValuePair<string, string> pair in arr)
            {
                String key = pair.Key;
                String val = pair.Value;
                xml += "<" + key + "><![CDATA[" + val + "]]></" + key + ">";
            }

            xml += "</xml>";
            return xml;
        }
        public static string FormatBizQueryParaMap(Dictionary<string, string> paraMap, bool urlencode)
        {
            string buff = "";
            try
            {
                paraMap = DictionarySort(paraMap);
                foreach (KeyValuePair<string, string> pair in paraMap)
                {
                    if (pair.Key != "")
                    {
                        string key = pair.Key;
                        string val = pair.Value;
                        if (urlencode)
                        {
                            val = System.Web.HttpUtility.UrlEncode(val);
                        }
                        buff += key.ToLower() + "=" + val + "&";
                    }
                }
                if (buff.Length == 0 == false)
                {
                    buff = buff.Substring(0, (buff.Length - 1) - (0));
                }
            }
            catch (Exception e)
            {
                //throw new SDKRuntimeException(e.Message);
            }
            return buff;
        }
        private static Dictionary<string, string> DictionarySort(Dictionary<string, string> dic)
        {
            Dictionary<string, string> rdic = new Dictionary<string, string>();
            List<KeyValuePair<string, string>> lst = new List<KeyValuePair<string, string>>(dic);
            lst.Sort(delegate (KeyValuePair<string, string> s1, KeyValuePair<string, string> s2)
            {
                return s1.Key.CompareTo(s2.Key);
            });
            dic.Clear();
            foreach (KeyValuePair<string, string> kvp in lst)
                rdic.Add(kvp.Key, kvp.Value);
            return rdic;
        }
        public static string MD5Encrypt(string input, Encoding encode)
        {
            System.Security.Cryptography.MD5 md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
            byte[] t = md5.ComputeHash(encode.GetBytes(input));
            StringBuilder sb = new StringBuilder(32);
            for (int i = 0; i < t.Length; i++)
                sb.Append(t[i].ToString("x").PadLeft(2, '0'));
            return sb.ToString();
        }
        public static string MD5Encrypt(string input)
        {
            return MD5Encrypt(input, new UTF8Encoding());
        }

        public static WeiXinModel.WxRedResultModel WxRed(WeiXinModel.WxRedModel model)
        {
            WxPayData sdata = new WxPayData();
            Dictionary<string, string> dic = new Dictionary<string, string>();
            sdata.SetValue("wxappid", WxPayConfig.APPID);
            sdata.SetValue("mch_id", WxPayConfig.MCHID);
            sdata.SetValue("re_openid", model.re_openid);
            sdata.SetValue("total_amount", model.total_amount);
            sdata.SetValue("nonce_str", model.nonce_str);
            sdata.SetValue("client_ip", model.client_ip);
            sdata.SetValue("mch_billno", model.mch_billno);
            sdata.SetValue("send_name", model.send_name);
            sdata.SetValue("wishing", model.wishing);
            sdata.SetValue("act_name", model.act_name);
            sdata.SetValue("remark", model.remark);
            sdata.SetValue("total_num", model.total_num);

            if( WxPayConfig.SceneId != "null" )
            {
                sdata.SetValue( "scene_id" , WxPayConfig.SceneId );//yanghao add 2016-9-9
            }
            string url = sdata.ToUrl();
            string strSginTemp = string.Format("{0}&key={1}", url, WxPayConfig.KEY);
            string sign = MD5Encrypt(strSginTemp).ToUpper();
            sdata.SetValue("sign", sign);
            dic.Add("wxappid", WxPayConfig.APPID);
            dic.Add("mch_id", WxPayConfig.MCHID);
            dic.Add("re_openid", model.re_openid);
            dic.Add("total_amount", model.total_amount);
            dic.Add("nonce_str", model.nonce_str);
            dic.Add("client_ip", model.client_ip);
            dic.Add("mch_billno", model.mch_billno);
            dic.Add("send_name", model.send_name);
            dic.Add("wishing", model.wishing);
            dic.Add("act_name", model.act_name);
            dic.Add("remark", model.remark);
            dic.Add( "total_num" , model.total_num );
            dic.Add("sign", sign);

            if( WxPayConfig.SceneId != "null" )
            {
                dic.Add( "scene_id" , WxPayConfig.SceneId );//yanghao add 2016-9-9
            }

            string xml = ArrayToXml(dic);
            string result = PayForWeiXin(xml);
            LogHelper.WriteInfoLog("RedPackage Send Record WxRed() 红包发送记录：" + result);           
            Dictionary<string, string> rdic = ReceivePostXmlData(result);
            return JsonMapper.ToObject<WeiXinModel.WxRedResultModel>(JsonMapper.ToJson(rdic));
        }


        /// <summary>
        /// 调用微信支付接口
        /// </summary>
        /// <param name="payForWeiXin"></param>
        /// <returns></returns>
        public static string PayForWeiXin(string postData)
        {
            string result = string.Empty;
            try
            {
                result = HttpService.Post(postData, "https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack", true, 15);
            }
            catch (Exception ex)
            {
                LogHelper.WriteErrorLog("WeiXinHelper.PayForWeiXin Happen ERROR: "+ex.Message + ">>>>> paramList postData=" + postData, ex);              
            }
            return result;
        }

        public static WeiXinModel.SelRedResultModel WeiXinRedResult(string mchBillNo)
        {
            string code = mchBillNo;
            Dictionary<string, string> dic = new Dictionary<string, string>();
            string guid = Guid.NewGuid().ToString().Replace("-", "");
            WxPayData sdata = new WxPayData();
            sdata.SetValue("appid", WxPayConfig.APPID);
            sdata.SetValue("mch_id", WxPayConfig.MCHID);
            sdata.SetValue("nonce_str", guid);
            sdata.SetValue("mch_billno", code);
            sdata.SetValue("bill_type", "MCHT");
            string url = sdata.ToUrl();
            string strSginTemp = string.Format("{0}&key={1}", url, WxPayConfig.KEY);
            string sign = MD5Encrypt(strSginTemp).ToUpper();
            sdata.SetValue("sign", sign);
            dic.Add("appid", WxPayConfig.APPID);
            dic.Add("mch_id", WxPayConfig.MCHID);
            dic.Add("nonce_str", guid);
            dic.Add("mch_billno", code);
            dic.Add("bill_type", "MCHT");
            dic.Add("sign", sign);
            string xml = ArrayToXml(dic);
            string result = HttpService.Post(xml, "https://api.mch.weixin.qq.com/mmpaymkttransfers/gethbinfo", true, 15);
            LogHelper.WriteInfoLog("RedPackage Send Record WeiXinRedResult() 红包发送记录结果查询：" + result);           
            Dictionary<string, string> rdic = ReceivePostXmlData(result);
            return JsonMapper.ToObject<WeiXinModel.SelRedResultModel>(JsonMapper.ToJson(rdic));
        }

       
        public static int SendMessage(string msgId, string msgBodyJson)
        {
            int state = 0;
            string wx_msgId = "";
            try
            {
                int sendStatus = SendMessageNew(msgBodyJson, out wx_msgId);
                if (!string.IsNullOrEmpty(wx_msgId)) state = 1;            
            }
            catch (Exception ex)
            {
               LogHelper.WriteErrorLog(msgId+"发送异常",ex);
            }
            return state;
        }

        /// <summary>
        /// 0:失败，1：成功，2：未关注
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="msgBodyJson"></param>
        /// <param name="wx_msgId"></param>
        /// <returns></returns>
        public static int SendMessageNew( string msgBodyJson, out string wx_msgId)
        {
            wx_msgId = "";
            string s = HttpService.Post(msgBodyJson,"https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" + GetToken().access_token);
            WeiXinModel.MessageResultModel result = JsonMapper.ToObject<WeiXinModel.MessageResultModel>(s);

            if (result.errmsg == "ok")
            {
                wx_msgId = result.msgid.ToString();
                return 1;
            }
            else
            {              
                LogHelper.WriteErrorLog("WeiXinHelper.SendMessageNew Happen ERROR: " + ">>>>> paramList msgBodyJson=" + msgBodyJson + " wx_msgId=" + wx_msgId, new Exception("SendMessage 发送客服消息到微信===，返回异常结果" + s));
                if (s.Contains("require subscribe hint")) return 2;
            }
            return 0;
        }
        public static void SendMessage(string msgBodyJson, out string wx_msgId)
        {
            wx_msgId = "";
            string s = HttpService.Post(msgBodyJson, "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" + GetToken().access_token);
            WeiXinModel.MessageResultModel result = JsonMapper.ToObject<WeiXinModel.MessageResultModel>(s);

            if (result.errmsg == "ok") wx_msgId = result.msgid.ToString();
            else
            {
                LogHelper.WriteErrorLog("WeiXinHelper.SendMessage Happen ERROR: " + ">>>>> paramList msgBodyJson=" + msgBodyJson + " wx_msgId=" + wx_msgId, new Exception("SendMessage 发送客服消息到微信===，返回异常结果" + s));              
            }
        }
        public static bool SendMessage2(string msgId , string openId, string msgContent , string url="" )
        {
            if (!string.IsNullOrEmpty(url))
            {
                WxPayData data = new WxPayData();
                data = WxPayApi.ShortUrl(data);
                if (data != null && data.GetValue("short_url") != null)
                    url = data.GetValue("short_url").ToString();
            }
            string msgBodyJson =  GetTextJson(openId, msgContent, url);
            string s = HttpService.Post(msgBodyJson, "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=" + GetToken().access_token);
            
            s = s.Replace("\"", "");
    
            bool isSuccess= false;
            if (s.Contains("{errcode:0,errmsg:ok}"))
            {
                isSuccess = true;
            }
            else if (s.Contains("subscription is canceled"))
            {
                //黑名单
            }
            else
            {
                LogHelper.WriteErrorLog("WeiXinHelper.SendMessage2 Happen ERROR: " + ">>>>> paramList msgId=" + msgId+ " openId="+ openId+ " url="+ url + " msgContent="+ msgContent, new Exception("SendMessage 发送客服消息到微信===，返回异常结果" + s));              
            }
            if (!string.IsNullOrEmpty(msgId))
            {
                // to do by chenqiang 
                //   return MessageHelper.UpdateTemplateMessage(msgId, "客服消息", isSuccess);
            }
            return isSuccess;
        }
        public static bool SendMessage3(string msgId, string openId, List<PicNewsInfo> list,out string responseStr)
        {
            responseStr = "";
            string msgBodyJson = GetPicNewsJson(openId,list);
            string s = HttpService.Post(msgBodyJson, "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=" + GetToken().access_token);

            s = s.Replace("\"", "");

            bool isSuccess = false;
            if (s.Contains("{errcode:0,errmsg:ok}"))
            {
                isSuccess = true;
            }
            else if (s.Contains("subscription is canceled"))
            {
                //黑名单
            }
            else
            {
                LogHelper.WriteErrorLog("WeiXinHelper.SendMessage3 Happen ERROR: " + ">>>>> paramList msgId=" + msgId, new Exception("SendMessage 发送客服消息到微信===，返回异常结果" + s));                 
            }
            responseStr = s;
            if (!string.IsNullOrEmpty(msgId))
            {
                // to do by chenqiang 
                //  return MessageHelper.UpdateTemplateMessage(msgId, "客服消息", isSuccess);
            }
            return isSuccess;
        }
        public static string GetPicNewsJson(string openId, List<PicNewsInfo> list)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append(" { ");
            sb.Append(" \"touser\" : \"" + openId + "\" ,");
            sb.Append(" \"msgtype\" : \"news\" ,");
            sb.Append(" \"news\" : {  ");
            sb.Append(" \"articles\" : [ ");
            for (int i=0;i<list.Count;i++)
            {
                PicNewsInfo item = list[i];
                sb.Append(" { \"title\" : \""+item.Title+ "\" , \"description\" : \"" + item.Description+ "\" , \"url\" : \""+item.ContentUrl+ "\" , \"picurl\" : \"" + item.PicUrl + "\" } ");
                if (i + 1 < list.Count) sb.Append(" , ");
            }
            sb.Append(" ] ");
            sb.Append(" }  } ");
            return sb.ToString().Replace("\\", "");
        }

        public static string DownloadImage(string mediaId, string productId)
        {
            try
            {
                string token = GetToken(AppID, AppSecret,true);
                WeiXinModel.TokedataDataModel tokedata = JsonMapper.ToObject<WeiXinModel.TokedataDataModel>(token);
                string downUrl = "https://api.weixin.qq.com/cgi-bin/media/get?access_token=" + tokedata.access_token +"&media_id=" + mediaId;

                string fileName = Guid.NewGuid().ToString("N") + ".jpg";
                string imgUrl = string.Format("/upload/product/{0}/{1}/{2}", DateTime.Now.ToString("yyyy-MM-dd"), productId,fileName);
                string filepath = HttpContext.Current.Server.MapPath("~/" + imgUrl);
                string dirPath = filepath.Replace("\\"+fileName, "");
                if (!Directory.Exists(dirPath))
                    Directory.CreateDirectory(dirPath);

                using (WebClient mywebclient = new WebClient())
                {
                    mywebclient.DownloadFile(downUrl, filepath);
                }

                return imgUrl;
            }
            catch (Exception ex)
            {
                LogHelper.WriteErrorLog("WeiXinHelper.DownloadImage Happen ERROR: " + ex.Message + ">>>>> paramList mediaId=" + mediaId, ex);                
                return "cuowu:="+ex.Message;
            }


        }

        public static string Post(string xml, string url)
        {
            return Post(xml, url, false, 20);
        }
        public static string Post(string xml, string url, bool isUseCert, int timeout)
        {
            return Post2(xml, url, isUseCert, timeout);
        }
        private static string Post2(string xml, string url)
        {
            return Post2(xml, url, false, 20);
        }
        public static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
        {
            //直接确认，否则打不开    
            return true;
        }
        private static string Post2(string xml, string url, bool isUseCert, int timeout)
        {
            System.GC.Collect();//垃圾回收，回收没有正常关闭的http连接

            string result = "";//返回结果

            HttpWebRequest request = null;
            HttpWebResponse response = null;
            Stream reqStream = null;

            try
            {
                //设置最大连接数
                ServicePointManager.DefaultConnectionLimit = 512;
                //设置https验证方式
                if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase))
                {
                    ServicePointManager.ServerCertificateValidationCallback =
                            new RemoteCertificateValidationCallback(CheckValidationResult);
                }

                /***************************************************************
                * 下面设置HttpWebRequest的相关属性
                * ************************************************************/
                request = (HttpWebRequest)WebRequest.Create(url);

                request.Method = "POST";
                request.Timeout = timeout * 1000;

                //设置代理服务器
                //WebProxy proxy = new WebProxy();                          //定义一个网关对象
                //proxy.Address = new Uri(WxPayConfig.PROXY_URL);              //网关服务器端口:端口
                //request.Proxy = proxy;

                //设置POST的数据类型和长度
                request.ContentType = "text/xml";
                byte[] data = System.Text.Encoding.UTF8.GetBytes(xml);
                request.ContentLength = data.Length;

                //是否使用证书
                if (isUseCert)
                {
                    string path = CommonHelper.GetAppSettings("WeiXin_PAY_ROOTPATH").ToString();
                    X509Certificate2 cert = new X509Certificate2(path + CommonHelper.GetAppSettings("WeiXin_PAY_SSLCERT_PATH").ToString(),
                        CommonHelper.GetAppSettings("WeiXin_PAY_SSLCERT_PASSWORD").ToString());
                    request.ClientCertificates.Add(cert);
                    LogHelper.WriteInfoLog("PostXml used cert");
                }

                //往服务器写入数据
                reqStream = request.GetRequestStream();
                reqStream.Write(data, 0, data.Length);
                reqStream.Close();

                //获取服务端返回
                response = (HttpWebResponse)request.GetResponse();

                //获取服务端返回数据
                StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
                result = sr.ReadToEnd().Trim();
                sr.Close();
            }
            catch (System.Threading.ThreadAbortException e)
            {
                LogHelper.WriteInfoLog("HttpService" + "Thread - caught ThreadAbortException - resetting.");
                LogHelper.WriteErrorLog("Exception message: {0}", e);
                System.Threading.Thread.ResetAbort();
            }
            catch (WebException e)
            {
                LogHelper.WriteInfoLog("HttpService WebException " + e.ToString() + e.Source + e.TargetSite + e.InnerException + e.StackTrace);
                if (e.Status == WebExceptionStatus.ProtocolError)
                {
                    LogHelper.WriteInfoLog("HttpService " + "StatusCode : " + ((HttpWebResponse)e.Response).StatusCode);
                    LogHelper.WriteInfoLog("ttpService " + "StatusDescription : " + ((HttpWebResponse)e.Response).StatusDescription);
                }
                throw new Exception(e.ToString());
            }
            catch (Exception e)
            {
                LogHelper.WriteInfoLog("HttpService " + e.ToString() + e.Source + e.TargetSite + e.InnerException + e.StackTrace);
                throw new Exception(e.ToString());
            }
            finally
            {
                //关闭连接和流
                if (response != null)
                {
                    response.Close();
                }
                if (request != null)
                {
                    request.Abort();
                }
            }
            return result;
        }

        public static string GetTextJson(string openId, string remark, string url = "")
        {
            if (string.IsNullOrEmpty(url))
            {
                if (remark.Length > 200) remark = remark.Substring(0, 197) + "...";
            }
            else
            {
                if (remark.Length > 175) remark = remark.Substring(0, 175) + "...";
                url = "";//url 转 短码
            }

            StringBuilder sb = new StringBuilder();
            sb.Append(" { ");
            sb.Append(" \"touser\" : \"" + openId + "\" ,");
            sb.Append(" \"msgtype\" : \"text\" ,");
            sb.Append(" \"text\"  : { \"content\" : \"" + remark + url + "\" } } ");
            sb.Append(" } ");
            return sb.ToString().Replace("\\", "");
        }

        public class PicNewsInfo
        {
            public string Title { get;set;}

            public string Description { get; set; }

            public string PicUrl { get; set; }

            public string ContentUrl { get; set; }
        }

    }
}